/*
 * print.cc
 *
 * This module prints out the hardware tree depending on options passed
 * Output can be plain text (good for human beings), HTML (good for web brow-
 * sers), XML (good for programs) or "hardware path" (ioscan-like).
 *
 */

#include "print.h"
#include "options.h"
#include "version.h"
#include "osutils.h"
#include <string.h>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <unistd.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <termios.h>

extern string ModemVendor;
extern string ModemDev;


__ID("@(#) $Id: print.cc 1907 2007-10-13 22:23:16Z lyonel $");

static unsigned int columns = 0, rows = 0;

static void init_wsize()
{
  struct winsize ws;
  char *env;

  if (!ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws))
  {
    rows = ws.ws_row;
    columns = ws.ws_col;
  }

  if (!rows)
  {
    env = getenv("LINES");
    if (env)
      rows = atoi(env);
    if (!rows)
      rows = 24;
  }

  if (!columns)
  {
    env = getenv("COLUMNS");
    if (env)
      columns = atoi(env);
    if (!columns)
      columns = 80;
  }
}


void print(hwNode & node,
bool html,
int level)
{

	if (node.getVendor().find("CMOTECH") != string::npos) {
		ModemVendor = node.getVendor();
		ModemDev = node.getLogicalName();
	}

	vector < string > config;
	vector < string > resources;
	config = node.getConfigValues("=");
	resources = node.getResources(":");

	for (unsigned int i = 0; i < node.countChildren(); i++) {
		print(*node.getChild(i), html, visible(node.getClassName()) ? level + 1 : 1);
	}
}


struct hwpath
{
  string path;
  string description;
  string devname;
  string classname;
};

static void printhwnode(hwNode & node, vector < hwpath > &l, string prefix = "")
{
  hwpath entry;

  entry.path = "";
  if (node.getPhysId() != "")
    entry.path = prefix + "/" + node.getPhysId();
  entry.description = node.asString();
  entry.devname = node.getLogicalName();
  entry.classname = node.getClassName();

  l.push_back(entry);
  for (unsigned int i = 0; i < node.countChildren(); i++)
  {
    printhwnode(*node.getChild(i), l, entry.path);
  }
}


static void printbusinfo(hwNode & node, vector < hwpath > &l)
{
  hwpath entry;

  entry.path = "";
  if (node.getBusInfo() != "")
    entry.path = node.getBusInfo();
  entry.description = node.asString();
  entry.devname = node.getLogicalName();
  entry.classname = node.getClassName();
  
  l.push_back(entry); 
  for (unsigned int i = 0; i < node.countChildren(); i++)
  { 
    printbusinfo(*node.getChild(i), l);
  }
}

static void printline(ostringstream & out)
{
  string s = out.str();

  if(isatty(STDOUT_FILENO) && (s.length()>columns))
    s.erase(columns);
  cout << s << endl;
  out.str("");
}


static void printincolumns( vector < hwpath > &l, const char *cols[])
{
  unsigned int l1 = strlen(cols[0]),
    l2 = strlen(cols[1]),
    l3 = strlen(cols[2]);
  unsigned int i = 0;
  ostringstream out;

  for (i = 0; i < l.size(); i++)
  {
    if (l1 < l[i].path.length())
      l1 = l[i].path.length();
    if (l2 < l[i].devname.length())
      l2 = l[i].devname.length();
    if (l3 < l[i].classname.length())
      l3 = l[i].classname.length();
  }

  out << cols[0];
  out << spaces(2 + l1 - strlen(cols[0]));
  out << cols[1];
  out << spaces(2 + l2 - strlen(cols[1]));
  out << cols[2];
  out << spaces(2 + l3 - strlen(cols[2]));
  out << cols[3];
  printline(out);

  out << spaces(l1 + l2 + l3 + strlen(cols[3]) + 6, "=");
  printline(out);

  for (i = 0; i < l.size(); i++)
    if (visible(l[i].classname.c_str()))
  {
    out << l[i].path;
    out << spaces(2 + l1 - l[i].path.length());
    out << l[i].devname;
    out << spaces(2 + l2 - l[i].devname.length());
    out << l[i].classname;
    out << spaces(2 + l3 - l[i].classname.length());
    out << l[i].description;
    printline(out);
  }
}


static const char *hwpathcols[] =
{
  "H/W path",
  "Device",
  "Class",
  "Description"
};

void printhwpath(hwNode & node)
{
  vector < hwpath > l;
  printhwnode(node, l);
  init_wsize();
  printincolumns(l, hwpathcols);
}


static const char *businfocols[] =
{
  "Bus info",
  "Device",
  "Class",
  "Description"
};

void printbusinfo(hwNode & node)
{
  vector < hwpath > l;
  printbusinfo(node, l);
  init_wsize();
  printincolumns(l, businfocols);
}
